package SearchTree;

import java.io.DataOutputStream;
import java.io.IOException;

public class SearchNode {
	
	static final int IntByteCount = 4;
	static final int CharByteCount = 2;
	static final int ByteByteCount = 4;
	
	static final byte IsFinish = 0x01;
	static final byte HasBrother = 0x02;
	static final byte HasChild = 0x04;
	
	byte info = 0;
	char key = 0;
	SearchNode brother = null;
	SearchNode child = null;
	
	int offChild = -1;
	int offset = 0;
	int length = 0;
	
	public SearchNode(char c) {
		key = c;
	}
	
	public SearchNode ForceGetMatchNode(char c) {
		SearchNode curNode = this, preNode = null;			
		while(curNode != null && curNode.key < c) {
			preNode = curNode;
			curNode = curNode.brother;
		}
		if(curNode == null || curNode.key > c) {
			SearchNode newNode = new SearchNode(c);
			newNode.SetBrother(curNode);
			if(preNode != null){
				preNode.SetBrother(newNode);
			}
			curNode = newNode;
		}
		return curNode;
	}
	
	protected int Prepare() {
		int brotherLen = 0;
		int childLen = 0;
		if(brother != null) {
			brotherLen = brother.Prepare();
		} 
		if(child != null) {
			childLen = child.Prepare();
			offChild = brotherLen;
		}
		return brotherLen + childLen + GetNodeSize();
	}
	
	protected void Export(DataOutputStream writer) throws IOException {
		writer.writeByte(key);
		writer.writeByte(info);
		if(Node(info, IsFinish)) {
			writer.writeInt(offset);
			writer.writeInt(length);
		}
		if(child != null) {
			writer.writeInt(offChild);			
		}
		
		if(brother != null) {
			brother.Export(writer);
		}
		if(child != null) {
			child.Export(writer);
		}
	}
	
	private void SetFlag(byte setBit) {
		info |= setBit;
	}
	
	private void ClearFlag(byte clearBit){
		info &= ~clearBit;
	}
	
	protected static boolean Node(byte info, byte testBit) {
		return (testBit & info) != 0;
	}
	
	protected void SetBrother(SearchNode node){
		brother = node;
		if(node == null){
			ClearFlag(HasBrother);
		}
		else{
			SetFlag(HasBrother);
		}
	}
	
	protected void SetChild(SearchNode node){
		child = node;
		if(node == null){
			ClearFlag(HasChild);
		}
		else{
			if(key == 'a' && node.key == 'A'){
				System.out.println();
			}
			SetFlag(HasChild);
		}
	}
	
	protected void SetFinish(int offset, int length){
		this.offset = offset;
		this.length = length;
		SetFlag(IsFinish);
	}
	
	private int GetNodeSize() {
		int size = CharByteCount;
		size += Node(info, IsFinish) ? IntByteCount * 2 : 0;
		size += Node(info, HasChild) ? IntByteCount : 0;
		return size;
	}
}
